package ms.maplestory.boot.connection.netty;

import ms.maplestory.boot.client.Client;
import ms.maplestory.boot.connection.crypto.Crypto;
import ms.maplestory.boot.packets.LoginPacket;
import ms.maplestory.boot.handlers.EventManager;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import ms.maplestory.boot.world.LoginServer;

import java.util.HashMap;
import java.util.Map;

import static ms.maplestory.boot.connection.netty.NettyClient.CLIENT_KEY;

@Slf4j(topic = "[Netty LoginAcceptor]")
public class LoginAcceptor implements Runnable {

    public static Map<String, Channel> channelPool = new HashMap<>();
    public LoginServer loginServer;

    @Override
    public void run() {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<SocketChannel>() {

                 @Override
                 protected void initChannel(SocketChannel ch) {
                     ch.pipeline().addLast(new PacketDecoder(), new ChannelHandler(), new PacketEncoder());
                     byte[] siv = new byte[]{70, 114, 30, 82};
                     byte[] riv = new byte[]{82, 48, 25, 115};
                     Client c = new Client(ch, siv, riv);
                     c.write(LoginPacket.sendConnect(riv, siv));
                     channelPool.put(c.getIP(), ch);
                     ch.attr(CLIENT_KEY).set(c);
                     ch.attr(Client.CRYPTO_KEY).set(new Crypto());
                     EventManager.addFixedRateEvent(c::sendPing, 0, 10000);
                 }
             }).childOption(ChannelOption.TCP_NODELAY, true)
             .childOption(ChannelOption.SO_KEEPALIVE, true);
            log.info("Login Service listening on port {}", loginServer.getPort());
            b.bind(loginServer.getPort()).sync().channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}
